#ifndef NODO_H
#define NODO_H

#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <memory>

using namespace std;

#include "tabla.h"

int nuevaEtq(void);
void prologo(Entrada e);
void epilogo(Entrada e);

/****************************************************************
La clase abstracta nodo provee la base para el árbol de
representación intermedio.

Las clases que hereden Nodo deban implementar las funciones 
generar(void) y mostrar(void).

La función generar(void) ha de generar el código ensamblador
correspondiente al nodo implementado.

La función mostrar(void) la utilizamos durante el proceso de 
desarollo, y sirven para mostrar el arbol de direcciones.

La función estática etiqueta y la variable estática int sirven 
para generar etiquetas con números de serie consecutivos. Los usan 
los nodos if y ifelse.
****************************************************************/
class Nodo {
 public:
  // Constructor por defecto
  virtual ~Nodo() {}
  virtual void generar(void) = 0;
  static string etiqueta(void);
 private:
  static int cont;
} ; // fin de la clase abstracta Nodo


/*****************************************************************
Definimos el tipo "CampoNodo" como un objeto del tipo 
std::auto_ptr de Nodo, que provee de "recolección de basura" para
los nodos hospedados en este campo.
****************************************************************/
typedef std::auto_ptr<Nodo> CampoNodo;


/*****************************************************************
Definimos el tipo "ListaParametros" como un objeto de vectores a 
punteros a objetos Nodo.
****************************************************************/
typedef std::vector<Nodo*> ListaParametros;


/*****************************************************************
NodoSecuencia representa una secuencia de nodos, que han de generarse
en según el orden de aparición en la gramática.
*****************************************************************/
class NodoSecuencia: public Nodo {
 private:
  CampoNodo sec, secs;
 public:
  NodoSecuencia(Nodo *sc,Nodo *scs) : sec(sc),secs(scs){}
  void generar(void);
}; // fin de la clase NodoSecuencia

/*****************************************************************
Implementa la construcción if, recibiendo una expresión de condición, y un
bloque de sentencias a ejecutar si se cumple la condición.
*****************************************************************/
class NodoIf: public Nodo {
 private:
  CampoNodo cond, cierto;
 public:
  NodoIf(Nodo *co,Nodo *i) :cond(co),cierto(i){}
  void generar(void);
}; // fin de la clase NodoIf

/*****************************************************************
Implementa la construcción if-else, recibiendo una expresión de condición, 
un bloque de sentencias a ejecutar si se cumple la condición, o otro a 
ejecutar si no se cumple
*****************************************************************/
class NodoIfElse: public Nodo {
 private:
  CampoNodo cond, cierto, falso;
 public:
  NodoIfElse(Nodo *co,Nodo *i,Nodo *e) :cond(co),cierto(i),falso(e){}
  void generar(void);
}; // fin de la clase NodoIf

/*****************************************************************
Implementa el salto incondicional de salida de función que devuelve 
un valor. Toma una expresión como ese valor
*****************************************************************/
class NodoRetorno: public Nodo {
 private:
  CampoNodo exp;
 public:
 NodoRetorno(Nodo *xp) : exp(xp){}
  void generar(void);
}; // fin de la clase NodoRetorno

/*****************************************************************
Implementa el salto incondicional de salida de función que no
devuelve ningun valor
*****************************************************************/
class NodoRetornoVacio: public Nodo {
 private:
  CampoNodo exp;
 public:
 NodoRetornoVacio() {}
  void generar(void);
}; // fin de la clase NodoRetorno

class NodoAsignacion : public Nodo {
 private:
  CampoNodo izq, expr;
 public:
  NodoAsignacion(Nodo *i, Nodo * e) : izq(i), expr(e) {}
  void generar(void);
} ; // fin de la clase NodoAsignacion


/*****************************************************************
Implementa el nodo menos unario, que produce la negación entera 
expresión asociada
*****************************************************************/
class NodoMenosUnario: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoMenosUnario(Nodo* nod): n(nod) {}
  void generar(void);
};

/*****************************************************************
Implementa el nodo más unario, que no produce ninguna modificación
a la expresión.
*****************************************************************/
class NodoMasUnario: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoMasUnario(Nodo* nod): n(nod) {}
  void generar(void);
};


/*****************************************************************
Implementa el nodo incremento prefijo, que toma un nodo parte_izquierda,
lo incrementa, y lo devuelve incrementado 
*****************************************************************/
class NodoIncPrefijo: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoIncPrefijo(Nodo* nod): n(nod) {}
  void generar(void);
};


/*****************************************************************
Implementa el nodo incremento prefijo, que toma un nodo parte_izquierda,
lo decrementa, y lo devuelve decrementado 
*****************************************************************/
class NodoDecPrefijo: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoDecPrefijo(Nodo* nod): n(nod) {}
  void generar(void);
};



/*****************************************************************
Implementa el nodo incremento sufijo, que toma un nodo parte_izquierda,
lo incrementa, preo devuelve el valor original de la parte_izquierda
*****************************************************************/
class NodoIncSufijo: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoIncSufijo(Nodo* nod): n(nod) {}
  void generar(void);
};



/*****************************************************************
Implementa el nodo decremento sufijo, que toma un nodo parte_izquierda,
lo decrementa, preo devuelve el valor original de la parte_izquierda
*****************************************************************/
class NodoDecSufijo: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoDecSufijo(Nodo* nod): n(nod) {}
  void generar(void);
};



/*****************************************************************
Implementa el nodo suma, que recibe dos nodos, que corresponden a
expresiones
*****************************************************************/
class NodoSuma: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoSuma(Nodo* i, Nodo* d): izq(i), der(d) {}
  void generar(void);
}; // fin de la clase NodoSuma



/*****************************************************************
Implementa el nodo resta, que recibe dos nodos, que corresponden a
expresiones
*****************************************************************/
class NodoResta: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoResta(Nodo* i, Nodo* d): izq(i), der(d) {}
  void generar(void);
}; // fin de la clase NodoResta



/*****************************************************************
Implementa el nodo multiplicacion, que recibe dos nodos, que 
corresponden a expresiones
*****************************************************************/
class NodoMult: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoMult(Nodo* i, Nodo* d): izq(i), der(d) {}
  void generar(void);
}; // fin de la clase NodoMult


/*****************************************************************
Implementa el nodo división, que recibe dos nodos, que 
corresponden a expresiones
*****************************************************************/
class NodoDivision: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoDivision(Nodo* i, Nodo* d): izq(i), der(d) {}
  void generar(void);
}; // fin de la clase NodoDivision



/*****************************************************************
Implementa el nodo módulo (resto entero), que recibe dos nodos, que 
corresponden a expresiones
*****************************************************************/
class NodoModulo: public Nodo {
 private:
  CampoNodo izq, der;
 public:
 NodoModulo(Nodo* i, Nodo* d): izq(i), der(d) {}
  void generar(void);
}; // fin de la clase NodoModulo



/*****************************************************************
Implementa el nodo llamada a función. Recive un nombre de función,
y una lista de parámetros.
*****************************************************************/
class NodoLlamada: public Nodo {
 public:
  NodoLlamada(string* nombre, ListaParametros* p): nom(nombre), params(p) {}
  ~NodoLlamada();
  void generar(void);
 private:
  std::auto_ptr<string> nom;
  std::auto_ptr<ListaParametros> params;
}; // fin de la clase NodoLlamada


/*****************************************************************
Implementa el nodo constante entera del programa.
*****************************************************************/
class NodoConstanteEntera: public Nodo {
 private:
  int num; 
 public:
 NodoConstanteEntera(int numero): num(numero) {}
  void generar(void);
}; // fin de la clase NodoConstanteEntera



/*****************************************************************
Implementa el nodo constante de cadena. Guardamos las constantes
de cadena como un hash estático del propio NodoConstanteCadena.

La clave con la que guardamos la cadena es un número entero, y 
utilizamos un contador para ir generando dichas claves.

En constructor del nodo almacena la nueva cadena en el hash, quedando 
así disponible a través del campo "etiqueta" de la clase.

Posteriormente, la función main() del traductor, genera la sección
.rodata con recorriendo tablaCadenas.
*****************************************************************/
class NodoConstanteCadena: public Nodo {
 private:
  string * nom;
  int etiqueta;
  static int cont;
 public:
  NodoConstanteCadena(string * nombre): nom(nombre) {
      if(tablaCadenas.find(*nombre) == tablaCadenas.end()) {
           etiqueta = cont++;
           tablaCadenas[*nombre] = etiqueta;
      }
      else
	  etiqueta = tablaCadenas[*nombre];
      
  }
  void generar(void);
  static map<string,int> tablaCadenas; 
}; // fin de la clase NodoConstanteCadena



/*****************************************************************
Implementa la parte izquierda de una expresión de asignación. En nuestra
implementación, se corresponde con un identificador, que ya ha sido
declarado previamente en el programa.
*****************************************************************/
class NodoIdentificadorLVal : public Nodo {
 private:
  Entrada e;
 public:
 NodoIdentificadorLVal(Entrada pE) : e(pE) {}
  void generar(void);
} ; // fin de la clase NodoIdentificadorLVal



/*****************************************************************
Implementa el nodo vacío. No genera ningún código. Se produce cuando
el programados escribe varios puntos y coma seguidos.
*****************************************************************/
class NodoVacio : public Nodo {
 public:
  void generar(void);
} ; // fin de la clase NodoVacio

	
/*****************************************************************
Implementa el nodo "LValue". Toma una "parte_izquierda" y devuelve 
su valor como expresión.
*****************************************************************/
class NodoLValue: public Nodo {
 private:
  CampoNodo n;
 public:
  NodoLValue(Nodo* nod): n(nod) {};
  void generar(void);
}; 
#endif
